﻿using System;
using System.Windows.Forms;
using AgateLib.DisplayLib;
using AgateLib.Geometry;
using AgateLib.InputLib;
using AgateLib.Sprites;
using AiAsteriods.Game.Entities.Base;
using AiAsteriods.Game.Entities.Enemies;
using AiAsteriods.Game.Entities.Projectile;
using AiAsteriods.Game.State;
using AiAsteriods.Game.Tools;

namespace AiAsteriods.Game.Entities.Agent {
  class Player : EntityAbstract {
    private static Config config;

    private FontSurface fontSmall;

    public double currentLife = 3;
    public double maxLife = 200;
    public int weaponFireInterval = 400;
    public int weaponDamage = 2;
    private new float maxSpeed;
    private float turnSpeed;
    private float moveSpeed;
    public bool IsDead { get; private set; }
    public static bool IsAwesome  = false;

    public bool isDummy;
    public delegate ActionType DecideMeth(int playerNum, GameStateAbstract gs);

    public int PlayerNum { get; set; }
    public DecideMeth Decide { get; set; }

    public Player(int playerNum, bool isDummy, DecideMeth decide, Sprite s, int x, int y, double speed, double rot, double radius, int collisionDamage, GameStateAbstract state)
      : base(s, x, y, rot, speed, radius, collisionDamage, 0, state) {
      fontSmall = new FontSurface("Verdana", 10);
      this.mySprite.SetScale(0.7f, 0.7f);
      this.PlayerNum = playerNum;
      this.isDummy = isDummy;
      IsDead = false;
      config = Global.GameStart.Config;
      moveSpeed = config.ShipMoveSpeed;
      maxSpeed = config.ShipMaxMoveSpeed;
      turnSpeed = config.ShipTurnSpeed;
      Decide = decide;
      //IsAwesome = config.DoubleShot;

      this.mySprite.Color = Color.White;
    }

    public override void Update(int delta) {
      if (X > Global.GameStart.ScreenWidth)
        X -= Global.GameStart.ScreenWidth;
      if (X < 0)
        X += Global.GameStart.ScreenWidth;

      if (Y > Global.GameStart.ScreenHeight)
        Y -= Global.GameStart.ScreenHeight;
      if (Y < 0)
        Y += Global.GameStart.ScreenHeight;

      if (!isDummy) {
        ActionType result = Decide(PlayerNum, Global.GameStart.CurrentState);
        switch (result) {
          case ActionType.ACCEL:
            Accel();
            break;
          case ActionType.BRAKE:
            Brake();
            break;
          case ActionType.FLEE:
            Flee();
            break;
          case ActionType.LEFT:
            Left();
            break;
          case ActionType.RIGHT:
            Right();
            break;
          case ActionType.SHOOT:
            Shoot();
            break;
          /*case ActionType.ORIGIN:
            Origin();
            break;*/
        }

        if (Keyboard.Keys[KeyCode.F])
          Flee();
        if (Keyboard.Keys[KeyCode.Left])
          Left();
        if (Keyboard.Keys[KeyCode.Right])
          Right();
        if (Keyboard.Keys[KeyCode.Up])
          Accel();
        if (Keyboard.Keys[KeyCode.Down])
          Brake();
        if (Keyboard.Keys[KeyCode.Space])
          Shoot();

        if (Keyboard.Keys[KeyCode.D1]) {
          IsAwesome = false;
          config.DoubleShot = false;
        }
        if (Keyboard.Keys[KeyCode.D2]) {
          IsAwesome = true;
          config.DoubleShot = true;
        }

        if (Keyboard.Keys[KeyCode.Escape] || Keyboard.Keys[KeyCode.Q]) {
          Keyboard.ReleaseKey(KeyCode.Escape);
          Application.Exit();
        }
      }
      base.Update(delta);
    }

    #region PLAYER ACTIONS
    public void Flee() {
      this.Speed -= moveSpeed;
      if (this.Speed < -maxSpeed)
        this.Speed = -maxSpeed;
    }

    public void Left() {
      this.Rotation += turnSpeed;
      this.Rotation %= 360;
      Brake();
    }

    public void Right() {
      this.Rotation -= turnSpeed;
      if (this.Rotation < 0)
        this.Rotation += 360;
      Brake();
    }

    public void Shoot() {
      GameStateAbstract state = Global.GameStart.CurrentState;
      Bullet bullet1 = BulletFactory.Get((int)X, (int)Y, config.BulletSpeed, Rotation, 4, 1, 0, state);
      state.AddEntity(bullet1);
      if (IsAwesome) {
        Bullet bullet2 = BulletFactory.Get((int)X, (int)Y, config.BulletSpeed, Rotation + 180, 4, 1, 0, state);
        state.AddEntity(bullet2);
      }
      Brake();
    }

    public void Accel() {
      this.Speed += moveSpeed;
      if (this.Speed > maxSpeed)
        this.Speed = maxSpeed;
    }

    public void Brake() {
      if (this.Speed > 0.1)
        Flee();
      else if (this.Speed < -0.1)
        Accel();
      else
        this.Speed = 0;
    }

    public void Origin() {
      PosF playerPos = new PosF((float)(X - PosF.Origin.x), (float)(Y - PosF.Origin.y));
      fontSmall.DrawText(0, 200, String.Format("R:{0:000}  T:{1:000}", Rotation, playerPos.theta));
      fontSmall.DrawText(0, 180, String.Format("P:({0},{1})  A:({2},{3})", X, Y, playerPos.x, playerPos.y));

      float desRot = new PosF((float)X,(float)Y).theta - playerPos.theta;
      desRot %= 360;
      if (desRot < 0)
        desRot += 360;
      fontSmall.DrawText(0, 220, String.Format("R:{0:000}  D:{1:000}", Rotation, desRot));

      if (Rotation < (desRot + config.ShipTurnSpeed + 1))
        Left();
      else if (Rotation > (desRot - config.ShipTurnSpeed - 1))
        Right();
      else {
        float distToCenter = new PosF((float)X, (float)Y).DistTo(PosF.Origin);
        if (distToCenter > 10)
          Accel();
        else
          Brake();
      }
    }
    #endregion

    #region OTHER
    public override void Draw() {
      base.Draw();
    }

    public double Distance(int x1, int y1, int x2, int y2) {
      double part1 = Math.Pow((x2 - x1), 2);
      double part2 = Math.Pow((y2 - y1), 2);
      double underRadical = part1 + part2;
      return Math.Sqrt(underRadical);
    }

    public override void Collide(EntityAbstract e) {
      if (e is Enemy) {
        IsDead = true;

        if (!config.GodMode)
          currentLife -= e.CollisionDamage;
      }
    }
    #endregion
  }
}